﻿using ELearning.Common;
using ELearning.Common.Converter;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;

namespace ELearning.DAL
{
    /// <summary>
    /// 仓储基类
    /// <remarks>创建：2019.6.17</remarks>
    /// </summary>
    public class BaseRepository<T> : IBaseRepository<T> where T : class
    {
        protected EduDbContext nContext = GetCurrentContext();
        public DataTableConvert<T> DataTableConverter = new DataTableConvert<T>();
        protected static EduDbContext GetCurrentContext()
        {
            EduDbContext _nContext = CallContext.GetData("WuLinELearningDbContext") as EduDbContext;
            if (_nContext == null)
            {
                _nContext = new EduDbContext();
                CallContext.SetData("WuLinELearningDbContext", _nContext);
            }
#if DEBUG
            _nContext.Database.Log = sql =>
            {
                System.Diagnostics.Debug.WriteLine(sql);
            };
            System.Diagnostics.Debug.WriteLine(_nContext.Database.Connection.ConnectionString);
#endif
            return _nContext;
        }
        public T Add(T entity)
        {
            nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Added;
            nContext.SaveChanges();
            return entity;
        }

        public int Adds(List<T> entitys)
        {
            foreach (var i in entitys)
            {
                nContext.Entry<T>(i).State = System.Data.Entity.EntityState.Added;
            }
            var n = nContext.SaveChanges();
            return n;
        }

        public int Count(Expression<Func<T, bool>> predicate)
        {
            return nContext.Set<T>().Count(predicate);
        }

        public bool Update(T entity)
        {
            nContext.Set<T>().Attach(entity);
            nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Modified;
            return nContext.SaveChanges() > 0;
        }

        public int Updates(List<T> entitys)
        {
            foreach (var i in entitys)
            {
                nContext.Entry<T>(i).State = System.Data.Entity.EntityState.Modified;
            }
            var n = nContext.SaveChanges();
            return n;
        }

        public bool Delete(T entity)
        {
            nContext.Set<T>().Attach(entity);
            nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Deleted;
            return nContext.SaveChanges() > 0;
        }

        /// <summary>
        /// 批量删除实体
        /// </summary>
        public bool Deletes(List<T> entitys)
        {
            foreach (var entity in entitys)
            {
                nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Deleted;
            }
            return nContext.SaveChanges() > 0;
        }

        public bool Exist(Expression<Func<T, bool>> anyLambda)
        {
            return nContext.Set<T>().Any(anyLambda);
        }

        public T Find(Expression<Func<T, bool>> whereLambda)
        {
            T _entity = nContext.Set<T>().FirstOrDefault<T>(whereLambda);
            return _entity;
        }

        public IList<T> FindList(string strSql, params object[] parameters)
        {
            return nContext.Database.SqlQuery<T>(strSql, parameters).ToList();
        }
        public IQueryable<T> FindList(Expression<Func<T, bool>> whereLamdba)
        {
            var _list = nContext.Set<T>().Where<T>(whereLamdba);
            return _list;
        }

        public IQueryable<T> FindList(Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc)
        {
            var _list = nContext.Set<T>().Where<T>(whereLamdba);
            _list = OrderBy(_list, orderName, isAsc);
            return _list;
        }

        public IQueryable<T> FindList(Expression<Func<T, bool>> whereLamdba, string path, string orderName, bool isAsc)
        {
            var _list = nContext.Set<T>().Include(path).Where<T>(whereLamdba);
            _list = OrderBy(_list, orderName, isAsc);
            return _list;
        }

        public IQueryable<T> FindPageList(int pageIndex, int pageSize, out int totalRecord, Expression<Func<T, bool>> whereLamdba, string orderName, bool isAsc)
        {
            var _list = nContext.Set<T>().Where<T>(whereLamdba);
            totalRecord = _list.Count();
            _list = OrderBy(_list, orderName, isAsc).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize);

            return _list;
        }
        /// <summary>
        /// Executes the <paramref name="commandText"/> with <paramref name="commandParameters"/> and return a data set.
        /// </summary>
        /// <param name="commandText">The command text.</param>
        /// <param name="commandParameters">The command parameters.</param>
        /// <returns></returns>
        protected DataSet ExecuteDataSet(string commandText, params SqlParameter[] commandParameters)
        {
            return SqlHelper.ExecuteDataset(nContext.Database.Connection.ConnectionString, CommandType.StoredProcedure, commandText, commandParameters);
        }
        /// <summary>
        /// Executes the store procedure.
        /// </summary>
        /// <param name="dataTableParameter">The data table parameter.</param>
        /// <returns></returns>
        protected IEnumerable<TResult> ExecuteStoreProcedure<TResult>(DataTableParameter dataTableParameter)
        {
            return nContext.Database.SqlQuery<TResult>(dataTableParameter.CommandText, dataTableParameter.SqlParameter);
        }
        /// <summary>
        /// 排序
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="source">原IQueryable</param>
        /// <param name="propertyName">排序属性名</param>
        /// <param name="isAsc">是否正序</param>
        /// <returns>排序后的IQueryable<T></returns>
        public IQueryable<T> OrderBy(IQueryable<T> source, string propertyName, bool isAsc)
        {
            if (source == null) throw new ArgumentNullException("source", "不能为空");
            if (string.IsNullOrEmpty(propertyName)) return source;
            var parameter = Expression.Parameter(typeof(T), "o");
            List<OrderModelField> orderByExpression = new List<OrderModelField>();
            if (propertyName.IndexOf(',') > -1)
            {
                foreach (var prop in propertyName.Split(','))
                {
                    if (prop.Split(' ').Count() == 2)
                    {
                        orderByExpression.Add(new OrderModelField { propertyName = prop.Split(' ')[0], IsDESC = prop.Split(' ')[1].ToUpper().Trim() == "DESC" ? true : false });
                    }
                    else
                    {
                        orderByExpression.Add(new OrderModelField { propertyName = prop.Split(' ')[0], IsDESC = isAsc });
                    }
                }
            }
            else
            {
                orderByExpression.Add(new OrderModelField { propertyName = propertyName, IsDESC = isAsc });
            }
            for (int i = 0; i < orderByExpression.Count; i++)
            {
                //根据属性名获取属性
                string str = orderByExpression[i].propertyName;
                var property = typeof(T).GetProperty(str);
                if (property == null) throw new ArgumentNullException("propertyName", "属性不存在");
                //创建一个访问属性的表达式
                var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                var orderByExp = Expression.Lambda(propertyAccess, parameter);

                string OrderName = "";
                if (i > 0)
                {
                    OrderName = orderByExpression[i].IsDESC ? "ThenByDescending" : "ThenBy";
                }
                else
                {
                    OrderName = orderByExpression[i].IsDESC ? "OrderByDescending" : "OrderBy";
                }
                MethodCallExpression resultExp = Expression.Call(typeof(Queryable), OrderName, new Type[] { typeof(T), property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
                source = source.Provider.CreateQuery<T>(resultExp);
            }
            return source;
        }


        public struct OrderModelField
        {
            public string propertyName { get; set; }
            public bool IsDESC { get; set; }
        }

        #region no savechanges

        public T AddNoSaveChange(T entity)
        {
            nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Added;
            return entity;
        }

        public int AddsNoSaveChange(List<T> entitys)
        {
            foreach (var i in entitys)
            {
                nContext.Entry<T>(i).State = System.Data.Entity.EntityState.Added;
            }
            return 1;
        }

        public bool UpdateNoSaveChange(T entity)
        {
            nContext.Set<T>().Attach(entity);
            nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Modified;
            return true;
        }

        public int UpdatesNoSaveChange(List<T> entitys)
        {
            foreach (var i in entitys)
            {
                nContext.Entry<T>(i).State = System.Data.Entity.EntityState.Modified;
            }
            return 1;
        }

        public bool DeleteNoSaveChange(T entity)
        {
            nContext.Set<T>().Attach(entity);
            nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Deleted;
            return true;
        }

        /// <summary>
        /// 批量删除实体
        /// </summary>
        public bool DeletesNoSaveChange(List<T> entitys)
        {
            foreach (var entity in entitys)
            {
                nContext.Entry<T>(entity).State = System.Data.Entity.EntityState.Deleted;
            }
            return true;
        }

        /// <summary>
        /// 事务提交
        /// </summary>
        public bool SaveChange()
        {
            return nContext.SaveChanges() > 0;
        }
        #endregion

        protected SqlParameter Now => new SqlParameter("@Now", DateTime.Now);

        protected DataTable ToDataTable(IList<T> entitys)
        {
            if (entitys.IsNotNullOrEmpty())
            {
                return DataTableConverter.ToDataTable(entitys);
            }
            else
            {
                return new DataTable();
            }
        }
        protected DataTable ToDataTable(T entity)
        {
            if (entity != null)
            {
                return DataTableConverter.ToDataTable(new List<T>() { entity });
            }
            else
            {
                return null;
            }
        }
    }
}
